home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / bccapp.zip / REPORT.C < prev    next >
C/C++ Source or Header  |  1991-09-15  |  9KB  |  502 lines

  1. /*
  2.  *
  3.  *    Report creation
  4.  *
  5.  * (C) 1990 Vision Software
  6.  *
  7.  * $Id: report.c 1.2002 91/05/04 16:24:47 pcalvin beta $
  8.  *
  9.  * Comments:
  10.  *
  11.  *    Generates trivial reports from a specific database. 
  12.  * Non-trivial reports (i.e relations etc) are not yet supported.
  13.  *
  14.  * Bugs:
  15.  *
  16.  *    None documented
  17.  */
  18. #include <string.h>
  19.  
  20. #include <stdhdr.h>
  21.  
  22. #include <adl.h>
  23. #include <report.h>
  24.  
  25. #include "lowlevel.h"
  26.  
  27. /*
  28.  *    Virtual Base class for report output.  Right now, we may
  29.  *    send reports to screen or printer. 
  30.  */
  31. class OUTPUT
  32.     {
  33. public:
  34.     OUTPUT(SZ szText,SZ szBar,PTL ptl,CCH cchMac);
  35.     VIRTUAL ~OUTPUT();
  36.     VIRTUAL VOID SendSz(SZ sz) = 0;
  37.     BOOL FContinue();
  38. protected:
  39.     VOID Title();
  40.     VOID Terminate();
  41.     ROW crowMac;
  42.     ROW crowCurrent;
  43.     SZ szTitleText;
  44.     SZ szTitleBar;
  45.     PTL ptlFirst;
  46. private:
  47.     CCH cchReportWidthMac;
  48.     BOOL fContinueReport;
  49.     };
  50.  
  51. /*
  52.  *    Screen reports.
  53.  */
  54. class SCREEN_OUTPUT : public OUTPUT
  55.     {
  56. public:
  57.     SCREEN_OUTPUT(SZ szText,SZ szBar,PTL ptl,CCH cchWidthMac,CTL ctl);
  58.     VIRTUAL ~SCREEN_OUTPUT();
  59.     VIRTUAL VOID SendSz(SZ sz);
  60. private:
  61.     WINDOW wnd;
  62.     };
  63.     
  64. /*
  65.  *    Printer  reports.
  66.  */
  67. class PRINTER_OUTPUT : public OUTPUT
  68.     {
  69. public:
  70.     PRINTER_OUTPUT(SZ szText,SZ szBar,PTL ptl,CCH cchWidthMac);
  71.     VIRTUAL ~PRINTER_OUTPUT();
  72.     VIRTUAL VOID SendSz(SZ sz);
  73.     };
  74.  
  75.     
  76. /*
  77.  *    Simple creation, we just need a database to start report from
  78.  */
  79. REPORT::REPORT(DATABASE &rdtbReport) : rdtb(rdtbReport)
  80.     {
  81.     penFirst = penNil;
  82.     penCurrent = penNil;
  83.     ptlFirst = ptlNil;
  84.     ptlCurrent = ptlNil;
  85.     ctlCurrent = ctlNil;
  86.     cchReportWidthMac = cchNil;
  87.     pfnFUsePdb = Nil;
  88.     }
  89.  
  90. REPORT::~REPORT()
  91.     {
  92.     PEN pen = penFirst;
  93.     PTL ptl = ptlFirst;
  94.  
  95.     /* 
  96.      *    Simply unload all the entries..
  97.      */
  98.     while (pen != penNil)
  99.         {
  100.         PEN penNext = pen->penNext;
  101.  
  102.         delete pen;
  103.  
  104.         pen = penNext;
  105.         }
  106.  
  107.     /*
  108.      *    And the titles..
  109.      */
  110.     while (ptl != ptlNil)
  111.         {
  112.         PTL ptlNext = ptl->ptlNext;
  113.  
  114.         delete ptl;
  115.  
  116.         ptl = ptlNext;
  117.         }
  118.     }
  119.     
  120. /*
  121.  *    Set filter for this report..
  122.  */
  123. VOID REPORT::SetFilterTo(BOOL (*pfnFUse)(DBASE *pdb))
  124.     {
  125.     pfnFUsePdb = pfnFUse;
  126.     }
  127.     
  128. /*
  129.  *    Create a new title for this report
  130.  */
  131. VOID REPORT::Title(SZ sz,AL al)
  132.     {
  133.     PointerAssert(sz);
  134.  
  135.     PTL ptl = new TL;
  136.  
  137.     /*
  138.      *    Create..
  139.      */
  140.     ptl->ptlNext = ptlNil;
  141.     ptl->sz = sz;
  142.     ptl->al = al;
  143.  
  144.     /*
  145.      *    Now, link in with the current list..
  146.      */
  147.      if (ptlFirst == ptlNil)
  148.          ptlFirst = ptl;
  149.      
  150.     if (ptlCurrent != ptlNil)
  151.         ptlCurrent->ptlNext = ptl;
  152.  
  153.     ptlCurrent = ptl;
  154.     ctlCurrent++;
  155.     }
  156.          
  157. /*
  158.  *    Create a new report column
  159.  */
  160. VOID REPORT::Entry(COL col,SZ sz,CCH cch,SZ szTitle)
  161.     {
  162.     Assert(sz != szNil);
  163.     
  164.     PEN pen = new EN;
  165.     
  166.     /*
  167.      *    Initialize the new Entry and then link with the rest..
  168.      */
  169.      pen->penPrev = penCurrent;
  170.      pen->penNext = penNil;
  171.      pen->col = col;
  172.      pen->sz = sz;
  173.      pen->cch = cch;
  174.      pen->szTitle = szTitle;
  175.  
  176.     /*
  177.      *    Allow for creation of the first in the chain..
  178.      */
  179.     if (penFirst == penNil)
  180.         penFirst = pen;
  181.      
  182.      if (penCurrent != penNil)
  183.          penCurrent->penNext = pen;
  184.  
  185.     /*
  186.      *    Keep track of the maximum width..
  187.      */
  188.     cchReportWidthMac = Max(cchReportWidthMac,col+cch);
  189.     
  190.     penCurrent = pen;
  191.     }
  192.  
  193. /*
  194.  *    Creates the report..
  195.  */
  196. VOID REPORT::Generate(BOOL fForward,BOOL fPrinter)
  197.     {
  198.     SZTEMP sz;
  199.     OUTPUT *popt;
  200.     BOOL (DATABASE:: *pfnInit)() = fForward ? DATABASE::FFirst : DATABASE::FLast;
  201.     BOOL (DATABASE:: *pfnTraverse)() = fForward ? DATABASE::FNext : DATABASE::FPrevious;
  202.     
  203.     /*
  204.      *    Create Title bar..
  205.      */
  206.      CreateTitle(szTitleText,szTitleBar);
  207.  
  208.     /*
  209.      *    Creates and Initializes the output device.
  210.      */
  211.     if (fPrinter)
  212.         popt = new PRINTER_OUTPUT(szTitleText,szTitleBar,ptlFirst,cchReportWidthMac);
  213.     else
  214.         popt = new SCREEN_OUTPUT(szTitleText,szTitleBar,ptlFirst,cchReportWidthMac,ctlCurrent);
  215.     
  216.      /*
  217.       *    Now, just traverse the database outputting each line
  218.       */
  219.      Verify((rdtb.*pfnInit)());
  220.  
  221.     do 
  222.         {
  223.         /*
  224.          *    Must check filter first..
  225.          */
  226.         if (pfnFUsePdb == Nil || pfnFUsePdb(rdtb.PdbQuery()))
  227.             {
  228.             CreateOutput(sz);
  229.  
  230.             popt->SendSz(sz);
  231.             }
  232.         }
  233.     while ((rdtb.*pfnTraverse)() && popt->FContinue());
  234.  
  235.     /*
  236.      *    Be sure to clean up our output device
  237.      */
  238.     delete popt;
  239.     }
  240.  
  241. /*
  242.  *    Creates the title bar and matching underline..
  243.  */
  244. VOID REPORT::CreateTitle(SZ szText,SZ szBar)
  245.     {
  246.     CCH cchMac = cchNil;
  247.     
  248.     memset(szText,' ',cchSzTempMax);
  249.     memset(szBar,' ',cchSzTempMax);
  250.  
  251.      for (PEN pen = penFirst; pen != penNil; pen = pen->penNext)
  252.          {
  253.          if (pen->sz != szNil)
  254.              {
  255.             strncpy(szText+pen->col,pen->szTitle,pen->cch);
  256.             memset(szBar+pen->col,'=',Max(pen->cch,strlen(pen->szTitle)));
  257.             }
  258.             
  259.          if (pen->cch + pen->col > cchMac)
  260.              cchMac = pen->cch + pen->col;
  261.         }
  262.  
  263.     OutputFix(szText,cchMac);
  264.     OutputFix(szBar,cchMac);
  265.     }
  266.  
  267. /*
  268.  *    Output line.  Called for each record..
  269.  */
  270. VOID REPORT::CreateOutput(SZ sz)
  271.     {
  272.     CCH cchMac = cchNil;
  273.     
  274.     memset(sz,' ',cchSzTempMax);
  275.  
  276.     /*
  277.      *    Build output line..
  278.      */
  279.     for (PEN pen = penFirst; pen != penNil; pen = pen->penNext)
  280.         {
  281.         strncpy(sz+pen->col,pen->sz,pen->cch);
  282.  
  283.         if (pen->cch + pen->col > cchMac)
  284.             cchMac = pen->cch + pen->col;
  285.         }
  286.     
  287.     OutputFix(sz,cchMac);
  288.     }
  289.  
  290. /*
  291.  *    Removes any embedded \0 up to cchMac.  Places \0 there
  292.  */
  293. VOID REPORT::OutputFix(SZ sz,CCH cchMac)
  294.     {
  295.     /* 
  296.      *    Place Nil at end..
  297.      */
  298.     sz[cchMac] = chNil;
  299.  
  300.     /*
  301.      *    Assert that any \0s within the text are removed..
  302.      */
  303.     for (CCH cch = cchNil; cch < cchMac; cch++)
  304.         {
  305.         if (sz[cch] == chNil)
  306.             sz[cch] = chSpace;
  307.         }
  308.     }
  309.  
  310. /*
  311.  *    Report Implementations.
  312.  */
  313. OUTPUT::OUTPUT(SZ szText,SZ szBar,PTL ptl,CCH cchMac)
  314.     {
  315.     szTitleText = szText;
  316.     szTitleBar = szBar;
  317.     ptlFirst = ptl;
  318.     fContinueReport = fTrue;
  319.     cchReportWidthMac = cchMac;
  320.     }
  321.  
  322. /*
  323.  *    Place holder for the destructor
  324.  */
  325. OUTPUT::~OUTPUT()
  326.     {
  327.     }
  328.  
  329. /*
  330.  *    Answer if the report should be Continued..
  331.  */
  332. BOOL OUTPUT::FContinue()
  333.     {
  334.     return (fContinueReport);
  335.     }
  336.  
  337. /*
  338.  *    Signals the termination of the report.
  339.  */
  340. VOID OUTPUT::Terminate()
  341.     {
  342.     fContinueReport = fFalse;
  343.     }
  344.  
  345. /*
  346.  *    Report titles..
  347.  */
  348. VOID OUTPUT::Title()
  349.     { 
  350.     PTL ptl = ptlFirst;
  351.  
  352.     /* 
  353.      *    Output the title..
  354.      */
  355.     while (ptl != ptlNil)
  356.         {
  357.         SZTEMP sz;
  358.         CCH cchLength = strlen(ptl->sz);
  359.         CCH cchOffset = cchNil;
  360.  
  361.         /*
  362.          *    Build the string/left/cented right
  363.          */
  364.         memset(sz,' ',cchSzTempMax);
  365.         
  366.         switch (ptl->al)
  367.             {
  368.         case alLeft:
  369.             cchOffset = cchNil;
  370.             break;
  371.         case alCentre:
  372.             cchOffset = (cchReportWidthMac >> 1) - (cchLength >> 1);
  373.             break;
  374.         case alRight:
  375.             cchOffset = cchReportWidthMac - cchLength;
  376.             break;
  377.             }
  378.             
  379.         /*
  380.          *    Now, pad the string with amount of spaces and output it..
  381.          */
  382.         strcpy(sz+cchOffset,ptl->sz);
  383.         SendSz(sz);
  384.  
  385.         ptl = ptl->ptlNext;
  386.         }
  387.     
  388.     /*
  389.      *    Output title/bar and reset cursor position
  390.      */
  391.     SendSz(szTitleText);
  392.     SendSz(szTitleBar);
  393.     }
  394.     
  395. /*
  396.  *    Screen output initialization.  Opens the window and displays
  397.  *    the first title/headings.
  398.  */
  399. SCREEN_OUTPUT::SCREEN_OUTPUT(SZ szText,SZ szBar,PTL ptl,CCH cchWidthMac,CTL ctl) : OUTPUT(szText,szBar,ptl,cchWidthMac)
  400.     {
  401.     crowMac = rowGlobalWindowBottom - 9 - ctl;
  402.     crowCurrent = rowNil;
  403.     wnd = WINDOW(4,3,rowGlobalWindowBottom-4,colGlobalWindowRight-3,coBlack,coCyan,szNil,fTrue);
  404.  
  405.     /*
  406.      *    Initialize window.  Set scroll region so that title bar appears 
  407.      *    all the time..
  408.      */
  409.     wnd.Open();
  410.     wnd.SetScrollRow(6+ctl,rowGlobalWindowBottom-4);
  411.  
  412.     /*
  413.      *    Output the title if any
  414.      */
  415.     Title();
  416.     
  417.     /*
  418.      * Since the TITLE is Fixed (I.e the window scrolls around it, reset
  419.      *    the row counter here.
  420.      */
  421.     crowCurrent = rowNil; 
  422.     }
  423.  
  424. /*
  425.  *    Remove the window..
  426.  */
  427. SCREEN_OUTPUT::~SCREEN_OUTPUT()
  428.     {
  429.     HELP hlp("Report finished, Press any key to continue");
  430.  
  431.     (VOID)CdInput();
  432.     
  433.     wnd.Close();
  434.     }
  435.  
  436. /*
  437.  *    A single line of the report..
  438.  */
  439. VOID SCREEN_OUTPUT::SendSz(SZ sz)
  440.     {
  441.     /*
  442.      *    Output the report line. 
  443.      */
  444.     wnd.Say(sz);
  445.  
  446.     /*
  447.      * For output to the screen, give the users a screenful at a time
  448.      */
  449.     if (++crowCurrent >= crowMac)
  450.         {
  451.         HELP hlp("Press ESC to Quit, any other key to continue");
  452.         
  453.         if (CdInput() == cdEscape)
  454.             Terminate();
  455.             
  456.         crowCurrent = rowNil;
  457.         }
  458.  
  459.     /*
  460.      *    If report is to continue, place the NL at the end
  461.      */
  462.     if (FContinue())
  463.         wnd.PutCh(chReturn);
  464.     }
  465.  
  466. /*
  467.  *    Printer initialization
  468.  */
  469. PRINTER_OUTPUT::PRINTER_OUTPUT(SZ szText,SZ szBar,PTL ptl,CCH cchWidthMac) : OUTPUT(szText,szBar,ptl,cchWidthMac)
  470.     {
  471.     crowMac = 60;
  472.     crowCurrent = rowNil;
  473.  
  474.     /*
  475.      *    Output the title if any
  476.      */
  477.     Title();
  478.     }
  479.  
  480. /*
  481.  *    Not much to do after the printer is finished
  482.  */
  483. PRINTER_OUTPUT::~PRINTER_OUTPUT()
  484.     {
  485.     }
  486.     
  487. /*
  488.  *    Send a single line to the printer.
  489.  */
  490. VOID PRINTER_OUTPUT::SendSz(SZ sz)
  491.     {
  492.     fprintf(stdprn,"%s\n",sz);
  493.     
  494.     if (++crowCurrent >= crowMac)
  495.         {
  496.         fprintf(stdprn,"\n\n\n\n\n\n");
  497.         fprintf(stdprn,"%s\n",szTitleText);
  498.         fprintf(stdprn,"%s\n",szTitleBar);
  499.         crowCurrent = 0;
  500.         }
  501.     }
  502.